/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.yuanrong.exception;

import com.yuanrong.errorcode.ErrorCode;
import com.yuanrong.errorcode.ErrorInfo;
import com.yuanrong.errorcode.ModuleCode;

import java.util.Objects;

/**
 * The type YR exception.
 *
 * @since 2023 /11/01
 */
public class YRException extends Exception {
    private ErrorCode errorCode;

    private ModuleCode moduleCode;

    private String errorMessage;

    /**
     * User native exception, reflected from StackTraceInfo
     */
    private Throwable cause;

    /**
     * Instantiates a new YRException.
     *
     * @param errorCode  the error code
     * @param moduleCode the module code
     * @param exception  the exception
     */
    public YRException(ErrorCode errorCode, ModuleCode moduleCode, Exception exception) {
        this.errorCode = errorCode;
        this.moduleCode = moduleCode;
        if (exception instanceof YRException) {
            YRException convertedException = (YRException) exception;
            this.errorMessage = convertedException.getErrorMessage();
        } else {
            this.errorMessage = exception.getMessage();
        }
        this.cause = exception;
    }

    /**
     * Instantiates a new YRException.
     *
     * @param errorInfo the ErrorInfo object
     */
    public YRException(ErrorInfo errorInfo) {
        this(errorInfo.getErrorCode(), errorInfo.getModuleCode(), errorInfo.getErrorMessage());
    }

    /**
     * Instantiates a new YR exception.
     *
     * @param errorCode    the error code
     * @param moduleCode   the module code
     * @param errorMessage the error message
     */
    public YRException(ErrorCode errorCode, ModuleCode moduleCode, String errorMessage) {
        this(errorCode, moduleCode, errorMessage, new Exception(errorMessage));
    }

    public YRException(ErrorCode errorCode, ModuleCode moduleCode, String errorMessage, Throwable cause) {
        this.errorCode = errorCode;
        this.moduleCode = moduleCode;
        this.errorMessage = errorMessage;
        this.cause = cause;
    }

    /**
     * Gets the error code of the exception.
     *
     * @return The ErrorCode object.
     */
    public ErrorCode getErrorCode() {
        return errorCode;
    }

    /**
     * Gets the module code of the exception.
     *
     * @return The ModuleCode object.
     */
    public ModuleCode getModuleCode() {
        return moduleCode;
    }

    /**
     * Gets the error message of the exception.
     *
     * @return The String error message.
     */
    public String getErrorMessage() {
        return errorMessage;
    }

    @Override
    public Throwable getCause() {
        return cause;
    }

    /**
     * When an YRException is thrown, this method is called and an error
     * message is generated by infomation from the errorInfo.
     *
     * @return String the exception message
     */
    @Override
    public String getMessage() {
        return "ErrorCode: " + this.errorCode + ", ModuleCode: " + this.moduleCode + ", ErrMsg: " + this.errorMessage;
    }

    @Override
    public void setStackTrace(StackTraceElement[] stackTrace) {
        super.setStackTrace(stackTrace);
    }

    /**
     * Overrides the 'equals' method to compare two YRException objects.
     *
     * @param obj The object to compare to.
     * @return True if the objects are equal, otherwise false.
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        YRException that = (YRException) obj;
        return this.errorCode == that.errorCode && this.moduleCode == that.moduleCode
                && Objects.equals(this.errorMessage, that.errorMessage);
    }

    /**
     * Overrides the 'hashCode' method to generate a hash code for the
     * YRException object.
     *
     * @return The hash code for the object.
     */
    @Override
    public int hashCode() {
        return Objects.hash(errorCode, moduleCode, errorMessage);
    }
}
